<?php

namespace App\Models\Scenic\Order;


use App\Models\Orders\Orders;
use App\Models\Scenic\ScenicOrder;
use App\Models\Scenic\ScenicSpotGoods;
use App\Models\Trip\OrderPay\OrderPay;
use App\Models\Trip\OrderPay\Repositories\Interfaces\OrderPayRepositoryInterface;
use App\Services\Scenic\ScenicOrderFactory;
use App\Trip\Enums\Scenic\ScenicProvider;
use App\Trip\Orders\TripOrderState;
use App\Trip\Repository\BaseRepository;
use Carbon\Carbon;
use Cls\Log;
use Illuminate\Support\Collection;
use Illuminate\Pagination\Paginator;
use Exception;
use Illuminate\Support\Facades\DB;
use Psy\Util\Str;

class ScenicOrderRepository extends BaseRepository
{
    public function __construct(ScenicOrder $model)
    {
        parent::__construct($model);
    }

    /**
     * @param array $param
     * @param int   $page_size
     * @return Collection
     * @throws Exception
     */
    public function lists(array $param, int $page_size): Collection
    {
        $total  = $this->listCommonQuery($param)
                       ->count();
        $isSort = isset($param['sort_key']) && isset($param['sort_value']) && in_array($param['sort_value'], [1, 2]);
        /**
         * @var Paginator $listData
         */
        $listData = $this->listCommonQuery($param)
                         ->with('passengers', function ($q) {
                             return $q->select([
                                 'order_sn',
                                 'truename',
                                 'ticket_price',
                                 'order_state',
                                 'passenger_id',
                                 'passenger_type',
                             ]);
                         })
                        ->with('order_goods', function ($q) {
                             return $q->select([
                                 'order_sn',
                                 'scenic_id',
                                 'ticket_id',
                                 'play_at',
                                 'price',
                                 'usage',
                                 'enter_type',
                                 'count',
                                 'contact',
                                 'verification_certificate',
                             ]);
                         })
                         ->when($isSort, function ($query) use ($param) {
                             $sort = [
                                 1 => "ASC",
                                 2 => "DESC",
                             ];
                             if ($param['sort_key'] == 'start_at') {
                                 $query->orderBy('play_at', $sort[$param['sort_value']]);
                             }

                             if ($param['sort_key'] == 'order_at') {
                                 $query->orderBy('created_at', $sort[$param['sort_value']]);
                             }
                         })
                         ->orderByDesc('id')
                         ->simplePaginate($page_size);


        $page_size    = $page_size == 0 ? 1 : $page_size;
        $last_page    = ceil($total / $page_size);
        $current_page = $listData->currentPage();
        $orders       = $listData->items();

        return collect(compact('orders', 'total', 'last_page', 'current_page'));
    }

    /**
     * @throws Exception
     */
    private function listCommonQuery(array $param)
    {

        return $this->model
            ->where(function ($query) use ($param) {
                if (isset($param['is_valid']) && $param['is_valid'] == 1) {
                    $query->whereIn('order_state', TripOrderState::valid_states());
                }
            })
            ->when(isset($param['order_state']) && $param['order_state'], function ($query) use ($param) {
                if (is_array($param['order_state'])) {
                    $query->whereIn('order_state', $param['order_state']);
                } else {
                    $query->where('order_state', $param['order_state']);
                }
            })
            ->when(isset($param['provider_pay_state']) && $param['provider_pay_state'], function ($query) use ($param) {
                if (is_array($param['provider_pay_state'])) {
                    $query->whereIn('provider_pay_state', $param['provider_pay_state']);
                } else {
                    $query->where('provider_pay_state', $param['provider_pay_state']);
                }
            })
            ->when(isset($param['order_sn']) && $param['order_sn'], function ($query) use ($param) {
                if (isset($param['order_sn']['operator'])) {
                    $query->where('order_sn', $param['order_sn']['operator'], $param['order_sn']['value']);
                } else {
                    $query->where('order_sn', $param['order_sn']);
                }
            })
            ->when(isset($param['trip_id']) && $param['trip_id'], function ($query) use ($param) {
                $query->where('trip_id', $param['trip_id']);
            })
            ->when(isset($param['user_id']), function ($query) use ($param) {
                $query->where('user_id', $param['user_id']);
            })
            ->where('delete_state', TripOrderState::DELETE_STATE_NOT_DELETE);
    }

    /**
     * @param array $param
     * @param bool  $to_show
     * @return Collection
     * @throws Exception
     */
    public function listAll(array $param, bool $to_show = true): Collection
    {
        $lists = $this->listCommonQuery($param)
                      ->orderByDesc('id')
                      ->get();
        if ($to_show) {
            return collect($lists)->map(fn($order_info) => $this->setOrderShowData($order_info));
        } else {
            return $lists;
        }
    }

    /**
     * @throws Exception
     */
    public function setOrderShowData(Orders $order): array
    {
        $scenic_order = $this->model->where('order_sn',$order->getOrderSn())->first();
        if (!$scenic_order instanceof ScenicOrder){
            throw new Exception(404,'门票订单不存在');
        }
        $order_passengers = ScenicOrderPassenger::where('order_sn',$order->getOrderSn())->get();
        $order_goods = ScenicOrderGoods::where('order_sn',$order->getOrderSn())->first();
        $scenic_goods = ScenicSpotGoods::where('ticket_id',$order_goods->ticket_id ?? '')->first();
        $passengers = [];
        foreach ($order_passengers as $passenger){
            $passengers[] = [
                'truename'=>$passenger->truename,
                'passenger_id'=>$passenger->passenger_id,
                'identity_type'=>$passenger->identity_type,
                'mobile'=>$passenger->mobile,
            ];
        }
        $verification_certificate = json_decode($order_goods->verification_certificate,true);
        $contact = json_decode($order_goods->contact,true);
        $provider = ScenicProvider::from($scenic_order->order_service);
        $scenicOrderProvider = (new ScenicOrderFactory())->findOneByProvider($provider);
        $providerOrderInfo= $scenicOrderProvider->orderDetail([
            'out_order_id' => $scenic_order->out_order_id,
        ]);
        $order_goods_info = [
            'ticket_id'=>$order_goods->ticket_id,
            'scenic_name'=>$providerOrderInfo['scenic_name'],
            'scenic_id'=>$scenic_goods->scenic_id,
            'ticket_name'=>$providerOrderInfo['ticket_name'],
            'play_at'=>$order_goods->play_at,
            'valid_date'=>$providerOrderInfo,
            'enter_type'=>$order_goods->enter_type,
            'verification_certificate'=>$verification_certificate,
            'ticket_office'=>$providerOrderInfo['ticket_office'],
            'ticket_delivery'=>$order_goods->ticket_delivery,
            'ticket_type'=>$order_goods->ticket_type,
            'book_number'=>$order_goods->count,
            'contact'=> $contact,
            'usage'=> $order_goods->usage,
        ];
        $order_info = [
            'order_sn'=>  $order->getOrderSn(),
            'trip_type'=>  $order->getTripType(),
            'order_state'=>  $order->getOrderState(),
            'order_amount'=>  $order->getOrderAmount(),
            'created_at'=>  $order->getCreatedAt(),
            'passengers'=>$passengers,
            'order_goods'=>$order_goods_info,
        ];
        $name = $scenic_goods->ticket_name  ?? '';
        $details = [
            [
                'type' => $scenic_goods->ticket_type ?? '',
                'name' => $name,
                'name_uy' => trans2uy($name),
                "total_price" => $order_goods->price,
                'count' => $order_goods->count,
            ]
        ];
        return [
            'order_info'=>$order_info,
            'price_details'=>$details,
        ];
    }


    private function orderIsPay(ScenicOrder $trip_order): bool
    {
        $orderPayRepo   = app(OrderPayRepositoryInterface::class);
        $pay_sn         = $trip_order->getPaysn();
        $order_pay_info = $pay_sn ? $orderPayRepo->findOneByPaySn($pay_sn) : null;
        if ($order_pay_info) {
            if ($order_pay_info->isPaySuccess()) {
                // 更新订单状态
                Log::error("门票取消订单失败:{$trip_order->getOrderSn()}，订单已支付");
                return true;
            } else if ($order_pay_info->isPayFailed() || $order_pay_info->isPayCancel()) {
                // 需要验证支付 到哪一步了
                return false;
            } else {
                // 如果是待支付 需要验证 支付结果 是否成功
                try {
                    return $order_pay_info->isPayResultDataSuccess();
                } catch (Exception $e) {
                    return false;
                }
            }
        } else {
            Log::error("门票取消订单，订单未支付，也未发起支付,order:{$trip_order->getOrderSn()},trip_no:{$trip_order->getTripNo()}");
        }
        return false;
    }


    /**
     * @param ScenicOrder $order
     * @param OrderPay   $orderPay
     * @return void
     * @throws Exception
     */
    public function orderPaid(ScenicOrder $order, OrderPay $orderPay)
    {
    }



    /**
     * @param string $out_order_sn
     * @return Collection
     */
    public function getOrdersByOutOrderSn(string $out_order_sn): Collection
    {
        return $this->findBy([
            'out_order_sn' => $out_order_sn,
        ]);
    }


    /**
     * @param string $out_order_id
     * @return ScenicOrder
     */
    public function getOneOrdersByOutOrderId(string $out_order_id): ScenicOrder
    {
        return $this->findOneBy([
            'out_order_id' => $out_order_id,
        ]);
    }

    /**
     * 出票中的订单
     * @param array $condition
     * @return Collection
     * @throws Exception
     */
    public function getTicketingOrders(array $condition = []): Collection
    {
        $condition['provider_pay_state'] = 1;// 供应商已支付
        $condition['pay_state']          = 1;// 已支付
        $condition['order_state']        = TripOrderState::ORDER_STATE_PAID;
        return $this->listCommonQuery($condition)->get();
    }

    /**
     * 更新供应商的支付状态
     * @param ScenicOrder $current_order
     * @param int        $pay_state
     * @param string     $desc
     * @return bool
     */
    public function updateProviderPayState(ScenicOrder $current_order, int $pay_state, string $desc): bool
    {
        $update_data = [
            'provider_pay_at'         => Carbon::now()->toDateTimeString(),
        ];
        // 更新供应商支付成功的时间
        if (1 == $pay_state && $desc == '') {
            $update_data['provider_pay_at'] = Carbon::now()->toDateTimeString();
        }
        return $this->update($update_data, $current_order);
    }

}